Imports System.DirectoryServices
Imports System.IO
Imports System.Text
Imports System.Collections.Generic


Partial Public Class frmActiveDirectory
    Inherits System.Windows.Forms.Form

    Const CONST_MESSAGE_GroupEnumeration As String = "Enumerating domain groups..."
    Const CONST_MESSAGE_GroupMembershipEnumeration As String = "Enumerating group membership..."
    Const CONST_MESSAGE_GroupMembershipComparison As String = "Performing membership comparison..."


    Dim ListOfGroups As New Collection
    Dim EmptyGroupBehavior As EmptyGroups

    Public Enum EmptyGroups As Integer
        Exclude
        Include
        ShowOnly
    End Enum

#Region " Windows Form Designer generated code "

    Friend WithEvents StatusStrip1 As System.Windows.Forms.StatusStrip
    Friend WithEvents StatusLabel As System.Windows.Forms.ToolStripStatusLabel
    Friend WithEvents chkShowNonMatchingGroups As System.Windows.Forms.CheckBox
    Friend WithEvents gbResults As System.Windows.Forms.GroupBox
    Friend WithEvents gbOptions As System.Windows.Forms.GroupBox
    Friend WithEvents Label6 As System.Windows.Forms.Label
    Friend WithEvents rbEmptyGroups_Exclude As System.Windows.Forms.RadioButton
    Friend WithEvents rbEmptyGroups_ShowOnly As System.Windows.Forms.RadioButton
    Friend WithEvents rbEmptyGroups_Include As System.Windows.Forms.RadioButton
    Friend WithEvents gbMatchDifferenceCount As System.Windows.Forms.GroupBox
    Friend WithEvents txtAllowedDifferenceCount As System.Windows.Forms.TextBox
    Friend WithEvents Label7 As System.Windows.Forms.Label
    Friend WithEvents rbMatches_AllowX As System.Windows.Forms.RadioButton
    Friend WithEvents rbMatches_ExactOnly As System.Windows.Forms.RadioButton
    Friend WithEvents Panel1 As System.Windows.Forms.Panel

    Public Sub New()
        MyBase.New()

        'This call is required by the Windows Form Designer.
        InitializeComponent()

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer
    Friend WithEvents Label1 As System.Windows.Forms.Label
    Friend WithEvents cmdLoadGroups As System.Windows.Forms.Button
    Friend WithEvents lbGroups As System.Windows.Forms.ListBox
    Friend WithEvents lbMatchingGroups As System.Windows.Forms.ListBox
    Friend WithEvents Label2 As System.Windows.Forms.Label
    Friend WithEvents Label3 As System.Windows.Forms.Label
    Friend WithEvents lbMatchingMembers As System.Windows.Forms.ListBox
    Friend WithEvents lbMembers As System.Windows.Forms.ListBox
    Friend WithEvents Label4 As System.Windows.Forms.Label
    Friend WithEvents Label5 As System.Windows.Forms.Label

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Friend WithEvents txtDomainFQDN As System.Windows.Forms.TextBox
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.txtDomainFQDN = New System.Windows.Forms.TextBox
        Me.Label1 = New System.Windows.Forms.Label
        Me.cmdLoadGroups = New System.Windows.Forms.Button
        Me.lbGroups = New System.Windows.Forms.ListBox
        Me.lbMatchingGroups = New System.Windows.Forms.ListBox
        Me.Label2 = New System.Windows.Forms.Label
        Me.Label3 = New System.Windows.Forms.Label
        Me.lbMatchingMembers = New System.Windows.Forms.ListBox
        Me.lbMembers = New System.Windows.Forms.ListBox
        Me.Label4 = New System.Windows.Forms.Label
        Me.Label5 = New System.Windows.Forms.Label
        Me.StatusStrip1 = New System.Windows.Forms.StatusStrip
        Me.StatusLabel = New System.Windows.Forms.ToolStripStatusLabel
        Me.chkShowNonMatchingGroups = New System.Windows.Forms.CheckBox
        Me.gbResults = New System.Windows.Forms.GroupBox
        Me.gbOptions = New System.Windows.Forms.GroupBox
        Me.Label6 = New System.Windows.Forms.Label
        Me.Panel1 = New System.Windows.Forms.Panel
        Me.rbEmptyGroups_Exclude = New System.Windows.Forms.RadioButton
        Me.rbEmptyGroups_ShowOnly = New System.Windows.Forms.RadioButton
        Me.rbEmptyGroups_Include = New System.Windows.Forms.RadioButton
        Me.gbMatchDifferenceCount = New System.Windows.Forms.GroupBox
        Me.txtAllowedDifferenceCount = New System.Windows.Forms.TextBox
        Me.Label7 = New System.Windows.Forms.Label
        Me.rbMatches_AllowX = New System.Windows.Forms.RadioButton
        Me.rbMatches_ExactOnly = New System.Windows.Forms.RadioButton
        Me.StatusStrip1.SuspendLayout()
        Me.gbResults.SuspendLayout()
        Me.gbOptions.SuspendLayout()
        Me.Panel1.SuspendLayout()
        Me.gbMatchDifferenceCount.SuspendLayout()
        Me.SuspendLayout()
        '
        'txtDomainFQDN
        '
        Me.txtDomainFQDN.Location = New System.Drawing.Point(99, 9)
        Me.txtDomainFQDN.Name = "txtDomainFQDN"
        Me.txtDomainFQDN.Size = New System.Drawing.Size(155, 20)
        Me.txtDomainFQDN.TabIndex = 2
        '
        'Label1
        '
        Me.Label1.AutoSize = True
        Me.Label1.Location = New System.Drawing.Point(12, 12)
        Me.Label1.Name = "Label1"
        Me.Label1.Size = New System.Drawing.Size(81, 13)
        Me.Label1.TabIndex = 3
        Me.Label1.Text = "Domain to load:"
        '
        'cmdLoadGroups
        '
        Me.cmdLoadGroups.Location = New System.Drawing.Point(76, 145)
        Me.cmdLoadGroups.Name = "cmdLoadGroups"
        Me.cmdLoadGroups.Size = New System.Drawing.Size(90, 24)
        Me.cmdLoadGroups.TabIndex = 4
        Me.cmdLoadGroups.Text = "Let's Go!"
        Me.cmdLoadGroups.UseVisualStyleBackColor = True
        '
        'lbGroups
        '
        Me.lbGroups.FormattingEnabled = True
        Me.lbGroups.Location = New System.Drawing.Point(21, 43)
        Me.lbGroups.Name = "lbGroups"
        Me.lbGroups.Size = New System.Drawing.Size(162, 212)
        Me.lbGroups.Sorted = True
        Me.lbGroups.TabIndex = 5
        '
        'lbMatchingGroups
        '
        Me.lbMatchingGroups.FormattingEnabled = True
        Me.lbMatchingGroups.Location = New System.Drawing.Point(202, 43)
        Me.lbMatchingGroups.Name = "lbMatchingGroups"
        Me.lbMatchingGroups.Size = New System.Drawing.Size(162, 212)
        Me.lbMatchingGroups.Sorted = True
        Me.lbMatchingGroups.TabIndex = 6
        '
        'Label2
        '
        Me.Label2.AutoSize = True
        Me.Label2.Location = New System.Drawing.Point(199, 27)
        Me.Label2.Name = "Label2"
        Me.Label2.Size = New System.Drawing.Size(88, 13)
        Me.Label2.TabIndex = 7
        Me.Label2.Text = "Matching Groups"
        '
        'Label3
        '
        Me.Label3.AutoSize = True
        Me.Label3.Location = New System.Drawing.Point(21, 27)
        Me.Label3.Name = "Label3"
        Me.Label3.Size = New System.Drawing.Size(80, 13)
        Me.Label3.TabIndex = 8
        Me.Label3.Text = "Domain Groups"
        '
        'lbMatchingMembers
        '
        Me.lbMatchingMembers.FormattingEnabled = True
        Me.lbMatchingMembers.Location = New System.Drawing.Point(202, 289)
        Me.lbMatchingMembers.Name = "lbMatchingMembers"
        Me.lbMatchingMembers.Size = New System.Drawing.Size(162, 147)
        Me.lbMatchingMembers.Sorted = True
        Me.lbMatchingMembers.TabIndex = 9
        '
        'lbMembers
        '
        Me.lbMembers.FormattingEnabled = True
        Me.lbMembers.Location = New System.Drawing.Point(21, 289)
        Me.lbMembers.Name = "lbMembers"
        Me.lbMembers.Size = New System.Drawing.Size(162, 147)
        Me.lbMembers.Sorted = True
        Me.lbMembers.TabIndex = 10
        '
        'Label4
        '
        Me.Label4.AutoSize = True
        Me.Label4.Location = New System.Drawing.Point(21, 273)
        Me.Label4.Name = "Label4"
        Me.Label4.Size = New System.Drawing.Size(82, 13)
        Me.Label4.TabIndex = 11
        Me.Label4.Text = "Group Members"
        '
        'Label5
        '
        Me.Label5.AutoSize = True
        Me.Label5.Location = New System.Drawing.Point(199, 273)
        Me.Label5.Name = "Label5"
        Me.Label5.Size = New System.Drawing.Size(82, 13)
        Me.Label5.TabIndex = 12
        Me.Label5.Text = "Group Members"
        '
        'StatusStrip1
        '
        Me.StatusStrip1.Items.AddRange(New System.Windows.Forms.ToolStripItem() {Me.StatusLabel})
        Me.StatusStrip1.Location = New System.Drawing.Point(0, 481)
        Me.StatusStrip1.Name = "StatusStrip1"
        Me.StatusStrip1.Size = New System.Drawing.Size(669, 22)
        Me.StatusStrip1.SizingGrip = False
        Me.StatusStrip1.TabIndex = 13
        Me.StatusStrip1.Text = "StatusStrip1"
        '
        'StatusLabel
        '
        Me.StatusLabel.BackColor = System.Drawing.Color.Transparent
        Me.StatusLabel.Name = "StatusLabel"
        Me.StatusLabel.Size = New System.Drawing.Size(127, 17)
        Me.StatusLabel.Text = "AD Group Comparison"
        '
        'chkShowNonMatchingGroups
        '
        Me.chkShowNonMatchingGroups.AutoSize = True
        Me.chkShowNonMatchingGroups.Location = New System.Drawing.Point(6, 19)
        Me.chkShowNonMatchingGroups.Name = "chkShowNonMatchingGroups"
        Me.chkShowNonMatchingGroups.Size = New System.Drawing.Size(176, 17)
        Me.chkShowNonMatchingGroups.TabIndex = 14
        Me.chkShowNonMatchingGroups.Text = "Include groups with no matches"
        Me.chkShowNonMatchingGroups.UseVisualStyleBackColor = True
        '
        'gbResults
        '
        Me.gbResults.Controls.Add(Me.Label3)
        Me.gbResults.Controls.Add(Me.lbGroups)
        Me.gbResults.Controls.Add(Me.lbMatchingGroups)
        Me.gbResults.Controls.Add(Me.Label2)
        Me.gbResults.Controls.Add(Me.Label5)
        Me.gbResults.Controls.Add(Me.lbMatchingMembers)
        Me.gbResults.Controls.Add(Me.Label4)
        Me.gbResults.Controls.Add(Me.lbMembers)
        Me.gbResults.Location = New System.Drawing.Point(272, 12)
        Me.gbResults.Name = "gbResults"
        Me.gbResults.Size = New System.Drawing.Size(383, 458)
        Me.gbResults.TabIndex = 16
        Me.gbResults.TabStop = False
        Me.gbResults.Text = "Results"
        '
        'gbOptions
        '
        Me.gbOptions.Controls.Add(Me.Label6)
        Me.gbOptions.Controls.Add(Me.Panel1)
        Me.gbOptions.Controls.Add(Me.chkShowNonMatchingGroups)
        Me.gbOptions.Location = New System.Drawing.Point(29, 234)
        Me.gbOptions.Name = "gbOptions"
        Me.gbOptions.Size = New System.Drawing.Size(200, 158)
        Me.gbOptions.TabIndex = 17
        Me.gbOptions.TabStop = False
        Me.gbOptions.Text = "Display Options"
        '
        'Label6
        '
        Me.Label6.AutoSize = True
        Me.Label6.Location = New System.Drawing.Point(26, 49)
        Me.Label6.Name = "Label6"
        Me.Label6.Size = New System.Drawing.Size(73, 13)
        Me.Label6.TabIndex = 15
        Me.Label6.Text = "Empty Groups"
        '
        'Panel1
        '
        Me.Panel1.Controls.Add(Me.rbEmptyGroups_Exclude)
        Me.Panel1.Controls.Add(Me.rbEmptyGroups_ShowOnly)
        Me.Panel1.Controls.Add(Me.rbEmptyGroups_Include)
        Me.Panel1.Location = New System.Drawing.Point(38, 65)
        Me.Panel1.Name = "Panel1"
        Me.Panel1.Size = New System.Drawing.Size(133, 75)
        Me.Panel1.TabIndex = 18
        '
        'rbEmptyGroups_Exclude
        '
        Me.rbEmptyGroups_Exclude.AutoSize = True
        Me.rbEmptyGroups_Exclude.Checked = True
        Me.rbEmptyGroups_Exclude.Location = New System.Drawing.Point(3, 3)
        Me.rbEmptyGroups_Exclude.Name = "rbEmptyGroups_Exclude"
        Me.rbEmptyGroups_Exclude.Size = New System.Drawing.Size(63, 17)
        Me.rbEmptyGroups_Exclude.TabIndex = 2
        Me.rbEmptyGroups_Exclude.TabStop = True
        Me.rbEmptyGroups_Exclude.Text = "Exclude"
        Me.rbEmptyGroups_Exclude.UseVisualStyleBackColor = True
        '
        'rbEmptyGroups_ShowOnly
        '
        Me.rbEmptyGroups_ShowOnly.AutoSize = True
        Me.rbEmptyGroups_ShowOnly.Location = New System.Drawing.Point(3, 49)
        Me.rbEmptyGroups_ShowOnly.Name = "rbEmptyGroups_ShowOnly"
        Me.rbEmptyGroups_ShowOnly.Size = New System.Drawing.Size(76, 17)
        Me.rbEmptyGroups_ShowOnly.TabIndex = 1
        Me.rbEmptyGroups_ShowOnly.Text = "Show Only"
        Me.rbEmptyGroups_ShowOnly.UseVisualStyleBackColor = True
        '
        'rbEmptyGroups_Include
        '
        Me.rbEmptyGroups_Include.AutoSize = True
        Me.rbEmptyGroups_Include.Location = New System.Drawing.Point(3, 26)
        Me.rbEmptyGroups_Include.Name = "rbEmptyGroups_Include"
        Me.rbEmptyGroups_Include.Size = New System.Drawing.Size(60, 17)
        Me.rbEmptyGroups_Include.TabIndex = 0
        Me.rbEmptyGroups_Include.Text = "Include"
        Me.rbEmptyGroups_Include.UseVisualStyleBackColor = True
        '
        'gbMatchDifferenceCount
        '
        Me.gbMatchDifferenceCount.Controls.Add(Me.txtAllowedDifferenceCount)
        Me.gbMatchDifferenceCount.Controls.Add(Me.Label7)
        Me.gbMatchDifferenceCount.Controls.Add(Me.rbMatches_AllowX)
        Me.gbMatchDifferenceCount.Controls.Add(Me.rbMatches_ExactOnly)
        Me.gbMatchDifferenceCount.Location = New System.Drawing.Point(29, 39)
        Me.gbMatchDifferenceCount.Name = "gbMatchDifferenceCount"
        Me.gbMatchDifferenceCount.Size = New System.Drawing.Size(200, 100)
        Me.gbMatchDifferenceCount.TabIndex = 18
        Me.gbMatchDifferenceCount.TabStop = False
        Me.gbMatchDifferenceCount.Text = "Match Behavior"
        '
        'txtAllowedDifferenceCount
        '
        Me.txtAllowedDifferenceCount.Location = New System.Drawing.Point(63, 41)
        Me.txtAllowedDifferenceCount.Name = "txtAllowedDifferenceCount"
        Me.txtAllowedDifferenceCount.Size = New System.Drawing.Size(36, 20)
        Me.txtAllowedDifferenceCount.TabIndex = 3
        '
        'Label7
        '
        Me.Label7.AutoSize = True
        Me.Label7.Location = New System.Drawing.Point(105, 44)
        Me.Label7.Name = "Label7"
        Me.Label7.Size = New System.Drawing.Size(59, 13)
        Me.Label7.TabIndex = 2
        Me.Label7.Text = "differences"
        '
        'rbMatches_AllowX
        '
        Me.rbMatches_AllowX.AutoSize = True
        Me.rbMatches_AllowX.Location = New System.Drawing.Point(14, 42)
        Me.rbMatches_AllowX.Name = "rbMatches_AllowX"
        Me.rbMatches_AllowX.Size = New System.Drawing.Size(50, 17)
        Me.rbMatches_AllowX.TabIndex = 1
        Me.rbMatches_AllowX.TabStop = True
        Me.rbMatches_AllowX.Text = "Allow"
        Me.rbMatches_AllowX.UseVisualStyleBackColor = True
        '
        'rbMatches_ExactOnly
        '
        Me.rbMatches_ExactOnly.AutoSize = True
        Me.rbMatches_ExactOnly.Checked = True
        Me.rbMatches_ExactOnly.Location = New System.Drawing.Point(14, 19)
        Me.rbMatches_ExactOnly.Name = "rbMatches_ExactOnly"
        Me.rbMatches_ExactOnly.Size = New System.Drawing.Size(146, 17)
        Me.rbMatches_ExactOnly.TabIndex = 0
        Me.rbMatches_ExactOnly.TabStop = True
        Me.rbMatches_ExactOnly.Text = "Show only exact matches"
        Me.rbMatches_ExactOnly.UseVisualStyleBackColor = True
        '
        'frmActiveDirectory
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.BackColor = System.Drawing.Color.Silver
        Me.ClientSize = New System.Drawing.Size(669, 503)
        Me.Controls.Add(Me.gbMatchDifferenceCount)
        Me.Controls.Add(Me.gbOptions)
        Me.Controls.Add(Me.gbResults)
        Me.Controls.Add(Me.StatusStrip1)
        Me.Controls.Add(Me.cmdLoadGroups)
        Me.Controls.Add(Me.Label1)
        Me.Controls.Add(Me.txtDomainFQDN)
        Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D
        Me.MaximizeBox = False
        Me.MinimizeBox = False
        Me.Name = "frmActiveDirectory"
        Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
        Me.Text = "AD Group Comparison"
        Me.StatusStrip1.ResumeLayout(False)
        Me.StatusStrip1.PerformLayout()
        Me.gbResults.ResumeLayout(False)
        Me.gbResults.PerformLayout()
        Me.gbOptions.ResumeLayout(False)
        Me.gbOptions.PerformLayout()
        Me.Panel1.ResumeLayout(False)
        Me.Panel1.PerformLayout()
        Me.gbMatchDifferenceCount.ResumeLayout(False)
        Me.gbMatchDifferenceCount.PerformLayout()
        Me.ResumeLayout(False)
        Me.PerformLayout()

    End Sub

#End Region

    Private Sub cmdClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Me.Close()
    End Sub

    Private Sub LoadADGroups()

        Cursor.Current = Cursors.WaitCursor

        ' Add some "pre-checking" code here to confirm that the Domain they've
        ' entered is valid and responsive. Hopefully, without waiting for
        ' 30 seconds for a timeout.

        AddGroups()
        AddUsers()
        FindMatchingGroups()

        StatusLabel.Text = "All Done!"

        Cursor.Current = Cursors.Default



    End Sub

    Public Sub AddGroups()

        Dim LoopCount As Long = 0

        Dim de As New DirectoryEntry("LDAP://" & Me.txtDomainFQDN.Text.Replace("/", "\/"))
        Dim searcher As New DirectorySearcher(de, "(&(objectCategory=group))")
        searcher.PropertiesToLoad.Add("distinguishedname")

        For Each result As SearchResult In searcher.FindAll()

            If LoopCount Mod 10 = 0 Then
                Me.StatusLabel.Text = CONST_MESSAGE_GroupEnumeration & _
                                              String.Format("({0} groups so far)", LoopCount)
                Application.DoEvents()
            End If

            If Not (IsNothing(result)) Then

                Dim DistinguishedName As String = CType(result.Properties("distinguishedname")(0), String)
                DistinguishedName = DistinguishedName.Replace("/", "\/")
                If Not Me.ListOfGroups.Contains(DistinguishedName) Then
                    Me.ListOfGroups.Add(New NamedCollection(DistinguishedName), _
                                                            DistinguishedName)
                End If

            End If

            LoopCount += 1

        Next

        searcher.Dispose()
        de.Dispose()

    End Sub


    Public Sub AddUsers()

        Dim LoopCount As Long = 0
        Dim loopTotal As Long = Me.ListOfGroups.Count
        Dim LoopIncrement As Long = Convert.ToInt64(loopTotal / 1000) + 1

        For Each group As NamedCollection In Me.ListOfGroups

            Dim de As New DirectoryEntry("LDAP://" & group.LongName)

            If group.ShortName = String.Empty Then
                group.ShortName = CType(de.Properties("sAMAccountName")(0), String)
            End If

            If LoopCount Mod LoopIncrement = 0 Then
                Me.StatusLabel.Text = CONST_MESSAGE_GroupMembershipEnumeration & _
                                          String.Format("({0}% complete)", _
                                          (Int(1000 * LoopCount / loopTotal) / 10).ToString)
                Application.DoEvents()
            End If

            For Each user As String In CType(de.Properties("member"), IEnumerable)

                Try
                    Dim Username As String = ADTypeConversion.DNtoSAM(user)
                    group.Members.Add(Username, Username)
                Catch ex As Exception

                End Try


            Next

            LoopCount += 1

            de.Dispose()

        Next

    End Sub

    Public Sub FindMatchingGroups()

        Dim LoopCount As Long = 0
        Dim LoopTotal As Long = Convert.ToInt64(Me.ListOfGroups.Count ^ 2)
        Dim LoopIncrement As Long = Convert.ToInt64(LoopTotal / 1000) + 1

        Dim GroupDifferenceLimit As Integer = AllowedMismatches()

        ' Clear group matches, in case we're refreshing
        For Each GroupFirst As NamedCollection In Me.ListOfGroups
            GroupFirst.MatchingGroups.Clear()
        Next

        For Each GroupFirst As NamedCollection In Me.ListOfGroups
            For Each GroupSecond As NamedCollection In Me.ListOfGroups
                Dim MismatchCount As Integer = 0

                If LoopCount Mod LoopIncrement = 0 Then
                    Me.StatusLabel.Text = CONST_MESSAGE_GroupMembershipComparison & _
                                          String.Format("({0}% complete)", _
                                          (Int(1000 * LoopCount / LoopTotal) / 10).ToString)
                    Application.DoEvents()
                End If

                If GroupFirst.LongName <> GroupSecond.LongName Then

                    Do

                        For Each de As DictionaryEntry In GroupFirst.Members
                            If Not GroupSecond.Members.Contains(de.Key) Then
                                MismatchCount += 1
                                If MismatchCount > GroupDifferenceLimit Then Exit Do
                            End If
                        Next

                        For Each de As DictionaryEntry In GroupSecond.Members
                            If Not GroupFirst.Members.Contains(de.Key) Then
                                MismatchCount += 1
                                If MismatchCount > GroupDifferenceLimit Then Exit Do
                            End If
                        Next

                        ' If we've gotten here, then the groups match
                        GroupFirst.MatchingGroups.Add(GroupSecond.LongName, GroupSecond.LongName)

                    Loop While 1 = 2

                End If

                LoopCount += 1

            Next
        Next

    End Sub

    Private Sub frmActiveDirectory_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.txtDomainFQDN.Text = Environment.UserDomainName
    End Sub

    Private Sub cmdLoadGroups_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdLoadGroups.Click

        LoadADGroups()

        ClearListBoxes()

        RefreshGroupList()

    End Sub

    Private Sub ClearListBoxes()

        Me.lbGroups.Items.Clear()
        Me.lbMembers.Items.Clear()
        Me.lbMatchingGroups.Items.Clear()
        Me.lbMatchingMembers.Items.Clear()

    End Sub

    Private Sub RefreshGroupList()
        For Each c As NamedCollection In Me.ListOfGroups
            If ((Me.EmptyGroupBehavior = EmptyGroups.Exclude And c.Members.Count > 0) Or _
                    (Me.EmptyGroupBehavior = EmptyGroups.Include) Or _
                    ((Me.EmptyGroupBehavior = EmptyGroups.ShowOnly And c.Members.Count = 0))) And _
                (chkShowNonMatchingGroups.Checked Or c.MatchingGroups.Count > 0) Then

                lbGroups.Items.Add(c.ShortName)
            End If

        Next

    End Sub

    Private Sub lbGroups_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lbGroups.SelectedIndexChanged

        Me.lbMatchingGroups.Items.Clear()

        RefreshMemberListBoxes()

        Dim group As NamedCollection = CType(ListOfGroups.Item(ADTypeConversion.SAMtoDN(Me.txtDomainFQDN.Text, Me.lbGroups.SelectedItem.ToString)), NamedCollection)

        ' Now, do the matching groups the same way
        For Each MatchingGroup As DictionaryEntry In group.MatchingGroups
            If ((Me.EmptyGroupBehavior = EmptyGroups.Exclude And group.Members.Count > 0) Or _
                (Me.EmptyGroupBehavior = EmptyGroups.Include) Or _
                ((Me.EmptyGroupBehavior = EmptyGroups.ShowOnly And group.Members.Count = 0))) And _
                (chkShowNonMatchingGroups.Checked Or group.MatchingGroups.Count > 0) Then

                Me.lbMatchingGroups.Items.Add(ADTypeConversion.DNtoSAM(MatchingGroup.Value.ToString))
            End If
        Next

    End Sub

    Private Sub lbMatchingGroups_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lbMatchingGroups.SelectedIndexChanged

        RefreshMemberListBoxes()

    End Sub

    Private Sub RefreshMemberListBoxes()

        Me.lbMembers.Items.Clear()
        Me.lbMatchingMembers.Items.Clear()

        ' First get the group members
        Dim group1 As NamedCollection = CType(ListOfGroups.Item(ADTypeConversion.SAMtoDN(Me.txtDomainFQDN.Text, Me.lbGroups.SelectedItem.ToString)), NamedCollection)

        Dim group2 As NamedCollection
        If Me.lbMatchingGroups.SelectedItems.Count > 0 Then
            group2 = CType(ListOfGroups.Item(ADTypeConversion.SAMtoDN(Me.txtDomainFQDN.Text, Me.lbMatchingGroups.SelectedItem.ToString)), NamedCollection)
        Else
            group2 = New NamedCollection()
        End If

        If group1.Members.Count = 0 Then
            Me.lbMembers.Items.Add("(This group is empty)")
        Else
            For Each username As DictionaryEntry In group1.Members
                If group2.Members.Contains(username.Value) Then
                    Me.lbMembers.Items.Add(username.Value)
                Else
                    Dim NameToAdd As String = username.Value.ToString
                    If Me.lbMatchingGroups.SelectedIndices.Count > 0 Then
                        NameToAdd += "*"
                    End If
                    Me.lbMembers.Items.Add(NameToAdd)
                End If
            Next
        End If

        If Me.lbMatchingGroups.SelectedIndices.Count = 0 Then
            ' Do nothing - no matching group is selected
        ElseIf group2.Members.Count = 0 Then
            Me.lbMatchingMembers.Items.Add("(This group is empty)")
        Else
            For Each username As DictionaryEntry In group2.Members
                If group1.Members.Contains(username.Value) Then
                    Me.lbMatchingMembers.Items.Add(username.Value)
                Else
                    Me.lbMatchingMembers.Items.Add(username.Value.ToString & "*")
                End If
            Next
        End If


    End Sub

    Private Sub OptionsCheckboxes_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
            Handles chkShowNonMatchingGroups.CheckedChanged

        ClearListBoxes()
        RefreshGroupList()

    End Sub

    Private Sub EmptyGroupRadio_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                Handles rbEmptyGroups_Exclude.CheckedChanged, rbEmptyGroups_Include.CheckedChanged, _
                        rbEmptyGroups_ShowOnly.CheckedChanged

        If Me.rbEmptyGroups_Exclude.Checked Then
            Me.EmptyGroupBehavior = EmptyGroups.Exclude
        ElseIf Me.rbEmptyGroups_Include.Checked Then
            Me.EmptyGroupBehavior = EmptyGroups.Include
        Else
            Me.EmptyGroupBehavior = EmptyGroups.ShowOnly
        End If

        ClearListBoxes()
        RefreshGroupList()

    End Sub

    Private Function AllowedMismatches() As Integer

        If Me.rbMatches_ExactOnly.Checked Then
            Return 0
        Else
            If IsNumeric(Me.txtAllowedDifferenceCount.Text) Then
                Return Convert.ToInt32(Me.txtAllowedDifferenceCount.Text)
            Else
                Return 0

            End If
        End If

    End Function

    Private Sub rbMatches_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
                Handles rbMatches_ExactOnly.CheckedChanged, rbMatches_AllowX.CheckedChanged

        If Me.rbMatches_ExactOnly.Checked Then
            Me.txtAllowedDifferenceCount.Enabled = False
        Else
            Me.txtAllowedDifferenceCount.Enabled = True
        End If

    End Sub

End Class
